using Crux.Core.Dapper.SqlGenerator;
using Crux.Core.Data;

namespace Crux.Core.Dapper;
public partial class QueryRepository<TContext> where TContext : DapperContext
{
    /// <inheritdoc/>
    public Pageable<TEntity> GetByPage<TEntity>(
        Expression<Func<TEntity, bool>> predicate,
        OrderExpression<TEntity> orderExpression,
        Expression<Func<TEntity, object>>? expr = null,
        bool ignoreFilter = false,
        PageOption option = default,
        Action<SqlGenerator<TEntity>>? configure = null,
        params Expression<Func<TEntity, object>>[] includes) where TEntity : class
    {
        if (predicate is null)
        {
            throw new ArgumentNullException(nameof(predicate));
        }

        uint limit = (uint)(option.PageSize ?? 0),
            offset = (uint)(((option.PageIndex ?? 1) - 1) * (option.PageSize ?? 0));

        var sqlQuery = GetSqlQuery(
            predicate: predicate,
            expr: expr,
            orderExpression: orderExpression,
            limit: limit,
            offset: offset,
            ignoreFilter: ignoreFilter,
            includes: includes,
            configure: configure);

        var totalCount = this.Count(predicate, ignoreFilter: ignoreFilter);

        var entities = Query<TEntity>(sqlQuery.GetSql(), sqlQuery.Param);

        return new Pageable<TEntity>(entities.AsQueryable(), option, totalCount);
    }
    /// <inheritdoc/>
    public async Task<Pageable<TEntity>> GetByPageAsync<TEntity>(
        Expression<Func<TEntity, bool>> predicate,
        OrderExpression<TEntity> orderExpression,
        Expression<Func<TEntity, object>>? expr = null,
        bool ignoreFilter = false,
        PageOption option = default,
        Action<SqlGenerator<TEntity>>? configure = null,
        CancellationToken cancellationToken = default,
        params Expression<Func<TEntity, object>>[] includes) where TEntity : class
    {
        if (predicate is null)
        {
            throw new ArgumentNullException(nameof(predicate));
        }

        uint limit = (uint)(option.PageSize ?? 0),
            offset = (uint)(((option.PageIndex ?? 1) - 1) * (option.PageSize ?? 0));

        var sqlQuery = GetSqlQuery(
            predicate: predicate,
            expr: expr,
            orderExpression: orderExpression,
            limit: limit,
            offset: offset,
            ignoreFilter: ignoreFilter,
            includes: includes,
            configure: configure);

        var totalCount = await this.CountAsync(predicate, ignoreFilter: ignoreFilter, cancellationToken: cancellationToken).ConfigureAwait(false);

        var entities = await QueryAsync<TEntity>(sqlQuery.GetSql(), sqlQuery.Param, cancellationToken).ConfigureAwait(false);

        return new Pageable<TEntity>(entities.AsQueryable(), option, totalCount);
    }

}